/*
 * Galaxium Messenger
 * 
 * Copyright (C) 2008 Paul Burton <paulburton89@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Collections.Generic;
using System.Xml.Serialization;

using Anculus.Core;

namespace Galaxium.Protocol.Msn.Soap.BodyParts
{
	public enum MemberType { Unknown, Passport, Email, Phone, Role, Group, Everyone }
	public enum MemberState { Unknown, Accepted }
	
	[XmlRoot (Namespace=SoapConstants.nsAddressBook)]
	[XmlInclude (typeof (PassportMember))]
	[XmlInclude (typeof (RoleMember))]
	[XmlInclude (typeof (EveryoneMember))]
	[XmlInclude (typeof (EmailMember))]
	[XmlInclude (typeof (PhoneMember))]
	[XmlInclude (typeof (GroupMember))]
	[XmlInclude (typeof (ServiceMember))]
	[XmlInclude (typeof (DomainMember))]
	public class Member
	{
		protected long _membershipId;
		protected bool _membershipIdSpecified = false;
		protected string _type;
		protected bool _typeSpecified = false;
		protected string _state;
		protected bool _stateSpecified = false;
		protected bool _deleted;
		protected bool _deletedSpecified = false;
		protected DateTime _lastChanged;
		protected bool _lastChangedSpecified = false;
		protected AnnotationCollection _annotations = null;
		protected bool _annotationsSpecified = false;
		
		public long MembershipId
		{
			get { return _membershipId; }
			set
			{
				_membershipId = value;
				_membershipIdSpecified = true;
			}
		}
		
		[XmlIgnore]
		public bool MembershipIdSpecified
		{
			get { return _membershipIdSpecified; }
			set { _membershipIdSpecified = value; }
		}
		
		[XmlElement ("Type")]
		public string _Type
		{
			get { return _type; }
			set
			{
				_type = value;
				_typeSpecified = true;
			}
		}
		
		[XmlIgnore]
		public MemberType Type
		{
			get
			{
				try
				{
					return (MemberType)Enum.Parse (typeof (MemberType), _type);
				}
				catch
				{
					Log.Warn ("Unknown value '{0}'", _type);
					return MemberType.Unknown;
				}
			}
			set { _Type = value.ToString (); }
		}
		
		[XmlIgnore]
		public bool TypeSpecified
		{
			get { return _typeSpecified; }
			set { _typeSpecified = value; }
		}
		
		[XmlElement ("State")]
		public string _State
		{
			get { return _state; }
			set
			{
				_state = value;
				_stateSpecified = true;
			}
		}
		
		[XmlIgnore]
		public bool StateSpecified
		{
			get { return _stateSpecified; }
			set { _stateSpecified = value; }
		}
		
		[XmlIgnore]
		public MemberState State
		{
			get
			{
				try
				{
					return (MemberState)Enum.Parse (typeof (MemberState), _state);
				}
				catch
				{
					Log.Warn ("Unknown value '{0}'", _state);
					return MemberState.Unknown;
				}
			}
			set { _State = value.ToString (); }
		}
		
		public bool Deleted
		{
			get { return _deleted; }
			set
			{
				_deleted = value;
				_deletedSpecified = true;
			}
		}
		
		[XmlIgnore]
		public bool DeletedSpecified
		{
			get { return _deletedSpecified; }
			set { _deletedSpecified = value; }
		}
		
		public DateTime LastChanged
		{
			get { return _lastChanged; }
			set
			{
				_lastChanged = value;
				_lastChangedSpecified = true;
			}
		}
		
		[XmlIgnore]
		public bool LastChangedSpecified
		{
			get { return _lastChangedSpecified; }
			set { _lastChangedSpecified = value; }
		}
		
		[XmlArray]
		[XmlArrayItem (Type=typeof (Annotation))]
		public AnnotationCollection Annotations
		{
			get { return _annotations; }
			set
			{
				_annotations = value;
				_annotationsSpecified = true;
			}
		}
		
		[XmlIgnore]
		public bool AnnotationsSpecified
		{
			get { return _annotationsSpecified; }
			set { _annotationsSpecified = value; }
		}
		
		public void AddAnnotation (string name, string val)
		{
			if (_annotations == null)
				Annotations = new AnnotationCollection ();
			
			_annotations.Add (new Annotation (name, val));
		}
		
		public virtual Member Clone ()
		{
			Member m = new Member ();
			
			m._annotations = _annotations.Clone ();
			m._annotationsSpecified = _annotationsSpecified;
			m._deleted = _deleted;
			m._deletedSpecified = _deletedSpecified;
			m._lastChanged = _lastChanged;
			m._lastChangedSpecified = _lastChangedSpecified;
			m._membershipId = _membershipId;
			m._membershipIdSpecified = _membershipIdSpecified;
			m._state = _state;
			m._stateSpecified = _stateSpecified;
			m._type = _type;
			m._typeSpecified = _typeSpecified;
			
			return m;
		}
		
		public virtual void ApplyDelta (Member m)
		{
			if (m == null)
				throw new NullReferenceException ();
			
			if (_annotationsSpecified)
			{
				if (m._annotationsSpecified)
					_annotations.ApplyDelta (m._annotations);
				else
					m.Annotations = _annotations.Clone ();
			}
			if (_deletedSpecified)
				m.Deleted = _deleted;
			if (_lastChangedSpecified)
				m.LastChanged = _lastChanged;
			if (_membershipIdSpecified)
				m.MembershipId = _membershipId;
			if (_stateSpecified)
				m._State = _state;
			if (_typeSpecified)
				m._Type = _type;
		}
	}
	
	public class MemberCollection : List<Member>
	{
		public Member this [long id]
		{
			get
			{
				foreach (Member mbr in this)
					if (mbr.MembershipId == id)
						return mbr;
				
				return null;
			}
			set
			{
				if (this[id] != null)
					Remove (this[id]);
				
				Add (value);
			}
		}
		
		public MemberCollection Clone ()
		{
			MemberCollection mc = new MemberCollection ();
			
			foreach (Member m in this)
				mc.Add (m.Clone ());
			
			return mc;
		}
	}
	
	// Used by regular msn contacts
	[XmlRoot ("Member", Namespace=SoapConstants.nsAddressBook)]
	public class PassportMember : Member
	{
		string _passportName;
		bool _passportNameSpecified = false;
		bool _isPassportNameHidden;
		bool _isPassportNameHiddenSpecified = false;
		long _passportId;
		bool _passportIdSpecified = false;
		long _cid;
		bool _cidSpecified = false;
		
		public string PassportName
		{
			get { return _passportName; }
			set
			{
				_passportName = value;
				_passportNameSpecified = true;
			}
		}
		
		[XmlIgnore]
		public bool PassportNameSpecified
		{
			get { return _passportNameSpecified; }
			set { _passportNameSpecified = value; }
		}
		
		public bool IsPassportNameHidden
		{
			get { return _isPassportNameHidden; }
			set { _isPassportNameHidden = value; }
		}
		
		[XmlIgnore]
		public bool IsPassportNameHiddenSpecified
		{
			get { return _isPassportNameHiddenSpecified; }
			set { _isPassportNameHiddenSpecified = value; }
		}
		
		public long PassportId
		{
			get { return _passportId; }
			set { _passportId = value; }
		}
		
		[XmlIgnore]
		public bool PassportIdSpecified
		{
			get { return _passportIdSpecified; }
			set { _passportIdSpecified = value; }
		}
		
		public long CID
		{
			get { return _cid; }
			set { _cid = value; }
		}
		
		[XmlIgnore]
		public bool CIDSpecified
		{
			get { return _cidSpecified; }
			set { _cidSpecified = value; }
		}
		
		public override Member Clone ()
		{
			PassportMember m = new PassportMember ();
			
			m._annotations = _annotations.Clone ();
			m._annotationsSpecified = _annotationsSpecified;
			m._deleted = _deleted;
			m._deletedSpecified = _deletedSpecified;
			m._lastChanged = _lastChanged;
			m._lastChangedSpecified = _lastChangedSpecified;
			m._membershipId = _membershipId;
			m._membershipIdSpecified = _membershipIdSpecified;
			m._state = _state;
			m._type = _type;
			
			m._cid = _cid;
			m._cidSpecified = _cidSpecified;
			m._isPassportNameHidden = _isPassportNameHidden;
			m._isPassportNameHiddenSpecified = _isPassportNameHiddenSpecified;
			m._passportId = _passportId;
			m._passportIdSpecified = _passportIdSpecified;
			m._passportName = _passportName;
			m._passportNameSpecified = _passportNameSpecified;
			
			return m;
		}
		
		public override void ApplyDelta (Member m)
		{
			base.ApplyDelta (m);
			
			PassportMember pm = m as PassportMember;
			
			if (pm == null)
			{
				Log.Warn ("Called on a non-PassportMember member: {0}", m);
				return;
			}
			
			if (_cidSpecified)
				pm.CID = _cid;
			if (_isPassportNameHiddenSpecified)
				pm.IsPassportNameHidden = _isPassportNameHidden;
			if (_passportIdSpecified)
				pm.PassportId = _passportId;
			if (_passportNameSpecified)
				pm.PassportName = _passportName;
		}
	}
	
	[XmlRoot ("Member", Namespace=SoapConstants.nsAddressBook)]
	public class EveryoneMember : Member
	{
	}
	
	[XmlRoot ("Member", Namespace=SoapConstants.nsAddressBook)]
	public class RoleMember : Member
	{
	}
	
	// EmailMember is used by non-msn contacts (eg. Yahoo)
	[XmlRoot ("Member", Namespace=SoapConstants.nsAddressBook)]
	public class EmailMember : Member
	{
		string _email;
		bool _emailSpecified = false;
		
		public string Email
		{
			get { return _email; }
			set
			{
				_email = value;
				_emailSpecified = true;
			}
		}
		
		[XmlIgnore]
		public bool EmailSpecified
		{
			get { return _emailSpecified; }
			set { _emailSpecified = value; }
		}
		
		public override Member Clone ()
		{
			EmailMember m = new EmailMember ();
			
			m._annotations = _annotations.Clone ();
			m._annotationsSpecified = _annotationsSpecified;
			m._deleted = _deleted;
			m._deletedSpecified = _deletedSpecified;
			m._lastChanged = _lastChanged;
			m._lastChangedSpecified = _lastChangedSpecified;
			m._membershipId = _membershipId;
			m._membershipIdSpecified = _membershipIdSpecified;
			m._state = _state;
			m._type = _type;
			
			m._email = _email;
			m._emailSpecified = _emailSpecified;
			
			return m;
		}
		
		public override void ApplyDelta (Member m)
		{
			base.ApplyDelta (m);
			
			EmailMember em = m as EmailMember;
			
			if (em == null)
			{
				Log.Warn ("Called on a non-EmailMember member: {0}", m);
				return;
			}
			
			if (_emailSpecified)
				em.Email = _email;
		}
	}
	
	[XmlRoot ("Member", Namespace=SoapConstants.nsAddressBook)]
	public class PhoneMember : Member
	{
		string _phone;
		bool _phoneSpecified;
		
		public string Phone
		{
			get { return _phone; }
			set
			{
				_phone = value;
				_phoneSpecified = true;
			}
		}
		
		[XmlIgnore]
		public bool PhoneSpecified
		{
			get { return _phoneSpecified; }
			set { _phoneSpecified = value; }
		}
		
		public override Member Clone ()
		{
			PhoneMember m = new PhoneMember ();
			
			m._annotations = _annotations.Clone ();
			m._annotationsSpecified = _annotationsSpecified;
			m._deleted = _deleted;
			m._deletedSpecified = _deletedSpecified;
			m._lastChanged = _lastChanged;
			m._lastChangedSpecified = _lastChangedSpecified;
			m._membershipId = _membershipId;
			m._membershipIdSpecified = _membershipIdSpecified;
			m._state = _state;
			m._type = _type;
			
			m._phone = _phone;
			m._phoneSpecified = _phoneSpecified;
			
			return m;
		}
		
		public override void ApplyDelta (Member m)
		{
			base.ApplyDelta (m);
			
			PhoneMember pm = m as PhoneMember;
			
			if (pm == null)
			{
				Log.Warn ("Called on non-PhoneMember member: {0}", m);
				return;
			}
			
			if (_phoneSpecified)
				pm.Phone = _phone;
		}
	}
	
	[XmlRoot ("Member", Namespace=SoapConstants.nsAddressBook)]
	public class GroupMember : Member
	{
	}
	
	[XmlRoot ("Member", Namespace=SoapConstants.nsAddressBook)]
	public class ServiceMember : Member
	{
	}
	
	[XmlRoot ("Member", Namespace=SoapConstants.nsAddressBook)]
	public class DomainMember : Member
	{
	}
}
